/*
 * Copyright (c) 2022 KCloud-Platform-Alibaba Authors. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 */
package org.laokou.common.core.utils;

import lombok.extern.slf4j.Slf4j;

/**
 * @author laokou
 */
@Slf4j
public class IdGenerator {

	/**
	 * 数据标识
	 */
	private static final long DATA_ID = 1L;

	/**
	 * 系统标识
	 */
	private static final long SYS_ID = 1L;

	/**
	 * 学花算法
	 */
	private static final Snowflake INSTANCE = new Snowflake(DATA_ID, SYS_ID);

	/**
	 * 默认雪花ID
	 */
	public static long defaultSnowflakeId() {
		return INSTANCE.nextId();
	}

	static class Snowflake {

		/**
		 * 起始的时间戳
		 */
		private final static long START_TIMESTAMP = 1480166465631L;

		/**
		 * 每一部分占用的位数 序列号占用的位数
		 */
		private final static long SEQUENCE_BIT = 13;

		/**
		 * 机器标识占用的位数
		 */
		private final static long MACHINE_BIT = 5;

		/**
		 * 数据中心占用的位数
		 */
		private final static long DATA_CENTER_BIT = 5;

		/**
		 * 每一部分的最大值
		 */
		private final static long MAX_SEQUENCE = ~(-1L << SEQUENCE_BIT);

		private final static long MAX_MACHINE_NUM = ~(-1L << MACHINE_BIT);

		private final static long MAX_DATA_CENTER_NUM = ~(-1L << DATA_CENTER_BIT);

		/**
		 * 每一部分向左的位移
		 */
		private final static long MACHINE_LEFT = SEQUENCE_BIT;

		private final static long DATA_CENTER_LEFT = SEQUENCE_BIT + MACHINE_BIT;

		private final static long TIMESTAMP_LEFT = DATA_CENTER_LEFT + DATA_CENTER_BIT;

		/**
		 * 数据中心ID
		 */
		private final long DATACENTER_ID;

		/**
		 * 机器标志ID
		 */
		private final long MACHINE_ID;

		/**
		 * 序列号
		 */
		private long sequence = 0L;

		/**
		 * 上一次时间戳
		 */
		private long lastTimeStamp = -1L;

		private long getNextMill() {
			long mill = getNewTimeStamp();
			while (mill <= lastTimeStamp) {
				mill = getNewTimeStamp();
			}
			return mill;
		}

		private long getNewTimeStamp() {
			return System.currentTimeMillis();
		}

		/**
		 * 根据指定的数据中心ID和机器标志ID生成指定的序列号
		 * @param dataCenterId 数据中心ID
		 * @param machineId 机器标志ID
		 */
		public Snowflake(final long dataCenterId, final long machineId) {
			if (dataCenterId > MAX_DATA_CENTER_NUM || dataCenterId < 0) {
				throw new RuntimeException("DtaCenterId can't be greater than MAX_DATA_CENTER_NUM or less than 0！");
			}
			if (machineId > MAX_MACHINE_NUM || machineId < 0) {
				throw new RuntimeException("MachineId can't be greater than MAX_MACHINE_NUM or less than 0！");
			}
			this.DATACENTER_ID = dataCenterId;
			this.MACHINE_ID = machineId;
		}

		/**
		 * 产生下一个ID
		 */
		public synchronized long nextId() {
			long currTimeStamp = getNewTimeStamp();
			if (currTimeStamp < lastTimeStamp) {
				throw new RuntimeException("Clock moved backwards.  Refusing to generate id");
			}

			if (currTimeStamp == lastTimeStamp) {
				// 相同毫秒内，序列号自增
				sequence = (sequence + 1) & MAX_SEQUENCE;
				// 同一毫秒的序列数已经达到最大
				if (sequence == 0L) {
					currTimeStamp = getNextMill();
				}
			}
			else {
				// 不同毫秒内，序列号置为0
				sequence = 0L;
			}

			lastTimeStamp = currTimeStamp;
			// 时间戳部分
			return (currTimeStamp - START_TIMESTAMP) << TIMESTAMP_LEFT
					// 数据中心部分
					| DATACENTER_ID << DATA_CENTER_LEFT
					// 机器标识部分
					| MACHINE_ID << MACHINE_LEFT
					// 序列号部分
					| sequence;
		}

	}

}